home *** CD-ROM | disk | FTP | other *** search
- PAGE ,132
- TITLE IBM-PC File Chain Program, Version 2.14, 21-Aug-1986
-
- ;
- ; Written By Steven Georgiades
- ;
- ; IBM-PC/XT File Chain Program
- ; Will respond with a list of the disk clusters that make up the file chain
- ; for the requested file.
- ;
- ; If you are using this program and find it of value, your
- ; contribution in any amount ($5.00 suggested) will be greatly
- ; appreciated. Makes checks payable to Steven M. Georgiades.
- ; Thank you.
- ;
- ; If you have any questions or comments about this or any other
- ; SMG program, call or write:
- ;
- ; Steven M. Georgiades
- ; 701-H South Hayward Street
- ; Anaheim, CA 92804
- ; (714) 826-9549
- ;
-
- CODE SEGMENT BYTE PUBLIC 'CODE'
-
- ASSUME CS:CODE,DS:CODE,ES:CODE,SS:CODE
-
- ORG 5CH
-
- FCB LABEL BYTE
-
- ORG 80H
-
- PARAM LABEL BYTE
-
- ORG 100H
-
- CHAIN: JMP BEGIN
-
- ANDSTR DB " , $"
- CHAINMSG1 DB "The Chain for $"
- CHAINMSG2 DB " is:",13,10,10,"$"
- CHAINMSG3 DB 13,10,10
- CHAINMSG4 DB "Total Clusters in File = XXXXX",13,10,10
- CHAINMSG5 DB "Physical File Length = XXXXXXXX",13,10
- CHAINMSG6 DB "Logical File Length = XXXXXXXX ("
- PERCENT DB " 0.00% Waste)",13,10,"$"
- CLSTSTR DB "XXXXX$"
- PRCNT100 DB "100.0"
- SIGNON DB "Chain, Version 2.14",13,10,10,"$"
- SPECERR DB "Invalid File or Path Specification",7,": $"
- THRUSTR DB " to$"
- CRLF DB 13,10,"$"
-
- CLSTSEC DW ?
- DIR_LEN DW ?
- DIRBUF DW ?
- DIRSEC DW ?
- DRIVE DB ?
- EOF DW 0FF8H
- FATSEC DW ?
- FATSIZE DB 3
- FILENAME DB 13 DUP(0)
- PREV DW ?
- RANGE DB 0
- SECSIZE DW ?
- SIZLSB DW ?
- SIZMSB DW ?
- STARTSEC DW ?
-
- FILESPEC DB "$",79 DUP(0)
-
- BEGIN: MOV AH,9 ; Output Sign-On Message
- MOV DX,OFFSET SIGNON
- INT 21H
- MOV AH,19H ; Get Default Drive
- INT 21H
- MOV DRIVE,AL ; and Save
- MOV SI,OFFSET PARAM ; Set up Pointer to Parameter
- LODSB ; Read Parameter Length
- CBW
- MOV BX,AX
- MOV BYTE PTR [SI][BX],0 ; Terminate Parameter String
- STRIP: LODSB ; Strip Off Leading Whitespace
- CMP AL,' '
- JE STRIP
- CMP AL,9
- JE STRIP
- OR AL,AL ; If End-of-Parameter, Error
- JNZ NO_ERR1
- JMP ERROR
- NO_ERR1: DEC SI ; ReUse Last Character
- MOV DI,OFFSET FILESPEC ; Point to FileSpec Buffer
- CMP BYTE PTR [SI+1],':' ; If 2nd Character is Colon,
- JNE GET_PATH
- SUB AL,'A' ; Get Drive Number
- MOV DRIVE,AL
- ADD SI,2 ; and Scan Past
- GET_PATH: MOV AL,DRIVE ; Get Drive Number
- ADD AL,'A' ; Convert to Drive Number
- STOSB ; in FileSpec
- MOV AL,':' ; Add Colon to FileSpec
- STOSB
- CMP BYTE PTR [SI],'\' ; If Next Character is not '\',
- JE COPYPATH
- MOV AL,'\'
- STOSB
- PUSH SI ; Get Current Path to FileSpec
- MOV SI,DI
- MOV AH,47H
- MOV DL,DRIVE
- INC DL
- INT 21H
- POP SI
- MOV AL,0 ; Find End-of-FileSpec
- MOV CX,64
- REPNE SCASB
- JE NO_ERR2
- JMP ERROR
- NO_ERR2: DEC DI
- CMP BYTE PTR [DI-1],'\' ; If Root DIR, Skip
- JE COPYPATH
- MOV AL,'\' ; End-of-FileSpec = '\'
- STOSB
- COPYPATH: LODSB ; Copy Rest of Parameter
- OR AL,AL ; to FileSpec
- JZ COPYDONE
- STOSB
- JMP SHORT COPYPATH
- COPYDONE: MOV AL,'$' ; Set End-of-FileSpec
- STOSB
- MOV DX,OFFSET FILESPEC ; Convert to Upper Case
- CALL UPPER
- MOV AL,DRIVE ; Read Boot Record
- MOV CX,1
- MOV DX,0
- MOV BX,OFFSET FATBUF
- INT 25H
- POPF
- MOV AX,FATBUF[11] ; Read Sector Size
- MOV SECSIZE,AX ; and Save
- MOV AL,BYTE PTR FATBUF[13] ; Read Sectors per Cluster
- XOR AH,AH
- MOV CLSTSEC,AX ; and Save
- MOV CX,FATBUF[14] ; Read # of Reserved Sectors
- MOV AL,BYTE PTR FATBUF[16] ; Read # of FAT's
- XOR AH,AH ; Convert to Word
- MOV BX,FATBUF[22] ; Read Sectors per FAT
- MOV FATSEC,BX
- MUL BX ; Calculate Total FAT Sectors
- ADD CX,AX ; Add to Reserved Sectors
- MOV AX,FATBUF[17] ; Read Number of DIR Entries
- MOV DIR_LEN,AX
- PUSH CX ; Calculate DIR Sectors
- MOV CL,5
- SHL AX,CL
- POP CX
- MOV BX,SECSIZE
- XOR DX,DX
- DIV BX
- OR DX,DX ; Adjust for Partial Sector
- JZ NO_ADD
- INC AX
- NO_ADD: MOV DIRSEC,AX ; Save DIR Sectors
- ADD CX,AX ; Add DIR Sectors to Reserved
- MOV STARTSEC,CX ; Save in STARTSEC
- MOV AX,FATSEC ; Calculate FAT Buffer Size
- MOV BX,SECSIZE
- MUL BX
- MOV BX,AX
- LEA AX,FATBUF[BX] ; Get DIR Buffer Pointer
- MOV DIRBUF,AX
- MOV AX,FATBUF[19] ; Read Total Sectors on Media
- SUB AX,CX ; Calculate Total Data Clusters
- MOV BX,CLSTSEC
- XOR DX,DX
- DIV BX
- CMP AX,4079 ; If Necessary, Adjust FAT Size
- JLE FAT_OK
- MOV FATSIZE,4
- MOV EOF,0FFF8H
- FAT_OK: MOV AL,DRIVE ; Read FAT
- MOV CX,FATSEC
- MOV DX,1
- MOV BX,OFFSET FATBUF
- INT 25H
- POPF
- MOV AL,DRIVE ; Read Root Directory
- MOV CX,DIRSEC
- MOV DX,STARTSEC
- SUB DX,CX
- MOV BX,DIRBUF
- INT 25H
- POPF
- MOV SI,OFFSET FILESPEC[3] ; Point to First Element of Path
- NEXT_FLD: MOV DI,OFFSET FILENAME ; Point to FileName Buffer
- NEXTCHAR: LODSB ; Copy Path Element to FileName
- CMP AL,'\' ; until '\' or '$'
- JE GOT_DIR
- CMP AL,'$'
- JE GOT_FNM
- STOSB
- JMP SHORT NEXTCHAR
- GOT_DIR: MOV AL,0 ; If '\', Read Subdirectory
- STOSB
- CALL READDIR
- JNC NEXT_FLD ; If No Error, Get Next Dir
- JMP ERROR ; Else Flag Error
- GOT_FNM: MOV AL,0 ; If '$',
- STOSB
- CALL SRCHFILE ; Read File DIR Info
- JNC NO_ERR3
- JMP ERROR ; If Error, Say So
- NO_ERR3: MOV AX,[BX+28] ; Read File Length
- MOV SIZLSB,AX
- MOV DX,[BX+30]
- MOV SIZMSB,AX
- MOV DI,OFFSET CHAINMSG6[31] ; Convert to ASCII
- CALL DEC8OUT ; Strip Off Leading Zeroes
- CALL STRIP0
- MOV AH,9 ; Output FileSpec Message
- MOV DX,OFFSET CHAINMSG1
- INT 21H
- MOV AH,9
- MOV DX,OFFSET FILESPEC
- INT 21H
- MOV AH,9
- MOV DX,OFFSET CHAINMSG2
- INT 21H
- MOV BX,[BX+26] ; Read Starting Cluster Number
- XOR CX,CX ; Cluster Count = 0
- OR BX,BX ; If Start Cluster = 0, Done
- JZ LASTCLST
- MOV AX,BX ; Output First Cluster Number
- CALL OUT_CLST
- MOV PREV,BX ; Previous Cluster = First
- INC CX ; Cluster Count = 1
- CALL NEXTCLST ; Get Next Cluster Number
- CMP BX,EOF ; If Last, Skip
- JNB LASTCLST
- CLSTLOOP: INC CX ; Increment Cluster Count
- MOV AX,PREV ; If Cluster is Previous + 1,
- INC AX
- CMP AX,BX
- JNE CLSTOUT
- MOV RANGE,-1 ; Set Range Flag
- JMP SHORT NEXTONE
- CLSTOUT: CMP RANGE,0 ; Else
- JE NORANGE ; If Range Flag is Set,
- MOV AH,9 ; Output " - "
- MOV DX,OFFSET THRUSTR
- INT 21H
- MOV AX,PREV ; Output Last Clstr in Range
- CALL OUT_CLST
- MOV RANGE,0 ; Reset Range Flag
- NORANGE: MOV AH,9 ; Output ", "
- MOV DX,OFFSET ANDSTR
- INT 21H
- MOV AX,BX ; Output Cluster Number
- CALL OUT_CLST
- NEXTONE: MOV PREV,BX ; Previous = Current
- CALL NEXTCLST ; Get Next Cluster Number
- CMP BX,EOF ; If Not EOF, Repeat
- JB CLSTLOOP
- CMP RANGE,0 ; If Range Flag is Set,
- JE LASTCLST
- MOV AH,2 ; Output " - "
- MOV DL,'-'
- INT 21H
- MOV AX,PREV ; Output Last Cluster of Range
- CALL OUT_CLST
- LASTCLST: MOV AX,SIZMSB ; If Size = 0, 100% Waste
- OR AX,SIZLSB
- JNZ NOT_ZERO
- MOV SI,OFFSET PRCNT100
- MOV DI,OFFSET PERCENT
- MOV CX,5
- REP MOVSB
- JMP SHORT CLSTCNT
- NOT_ZERO: MOV AX,SECSIZE ; Calculate Percent Waste
- MOV BX,CLSTSEC
- MUL BX
- MOV BX,AX
- MUL CX
- SUB AX,SIZLSB
- MOV DX,100
- MUL DX
- DIV BX
- PUSH DX
- XOR DX,DX
- DIV CX
- PUSH DX
- MOV DI,OFFSET PERCENT[2] ; Convert Percent to ASCII
- CALL DEC2OUT
- CALL STRIP0
- POP AX
- MUL BX
- POP DI
- ADD AX,DI
- ADC DX,0
- DIV CX
- MOV DX,100
- MUL DX
- DIV BX
- MOV DI,OFFSET PERCENT[5]
- CALL DEC2OUT
- CLSTCNT: MOV AX,CX ; Convert Cluster Count to ASCII
- MOV DI,OFFSET CHAINMSG4[31]
- CALL DEC5OUT
- CALL STRIP0 ; Strip Off Leading Zeroes
- MOV AX,CLSTSEC ; Calculate Physical File Size
- MUL CX
- MOV CX,SECSIZE
- MUL CX
- MOV DI,OFFSET CHAINMSG5[31] ; Convert to ASCII
- CALL DEC8OUT
- CALL STRIP0 ; Strip Off Leading Zeroes
- MOV AH,9 ; Output Trailer Message
- MOV DX,OFFSET CHAINMSG3
- INT 21H
- MOV AX,4C00H ; Exit to DOS
- INT 21H
- ERROR: MOV AH,9 ; Output Error Message
- MOV DX,OFFSET SPECERR
- INT 21H
- MOV AH,9
- MOV DX,OFFSET FILESPEC ; Output FileSpec
- INT 21H
- MOV AH,9
- MOV DX,OFFSET CRLF
- INT 21H
- MOV AX,4C01H ; Exit to DOS
- INT 21H
-
- SRCHFILE: PUSH AX ; Save Register
- PUSH CX
- PUSH DI
- PUSH SI
- CMP FILENAME,'.' ; If Filename Starts with '.',
- JNE SRCHFIL2
- MOV SI,OFFSET FILENAME ; Copy Filename to FCB
- MOV DI,OFFSET FCB[1]
- MOV CX,11
- SRCHFIL1: LODSB
- STOSB
- OR AL,AL
- LOOPNZ SRCHFIL1
- INC CX ; and Pad With Spaces
- DEC DI
- MOV AL,' '
- REP STOSB
- JMP SHORT SRCHFIL3
- SRCHFIL2: MOV AX,2900H ; Else Parse Filename
- MOV SI,OFFSET FILENAME
- MOV DI,OFFSET FCB
- INT 21H
- SRCHFIL3: MOV DI,OFFSET FCB[1] ; Point to Filename in FCB
- MOV SI,DIRBUF ; Point to Start of DIRBUF
- MOV CX,DIR_LEN ; Load DIR Length
- JCXZ SRCHFIL5 ; If Zero, Not Found
- SRCHFIL4: PUSH CX ; Save Registers
- PUSH DI
- PUSH SI
- MOV CX,11 ; Compare Filename
- REPE CMPSB
- POP SI ; Restore Registers
- POP DI
- POP CX
- JE SRCHFIL6 ; If Match, Found
- ADD SI,32 ; Else Next DIR Entry
- LOOP SRCHFIL4 ; and Repeat
- SRCHFIL5: STC ; Set Error Flag
- JMP SHORT SRCHFIL7 ; Done
- SRCHFIL6: MOV BX,SI ; Set Pointer to DIR Entry
- CLC ; Clear Error Flag
- SRCHFIL7: POP SI ; Restore Registers
- POP DI
- POP CX
- POP AX
- RET ; Done
-
- READDIR: PUSH CX ; Save Registers
- PUSH DI
- PUSH SI
- CALL SRCHFILE ; Search for DIR
- JC READDIR2 ; If Not Found, Error
- MOV BX,[BX+26] ; Get Starting Cluster Number
- MOV DIR_LEN,0 ; DIR Length = 0
- OR BX,BX ; If Start Cluster = 0, Error
- JZ READDIR2
- MOV AX,SECSIZE ; Calculate DIR Entries/Cluster
- MOV CX,CLSTSEC
- MUL CX
- MOV CL,5
- SHR AX,CL
- MOV CX,AX
- MOV DI,DIRBUF ; Point to DIR Buffer
- READDIR1: CALL READCLST ; Read Cluster
- ADD DIR_LEN,CX ; Increment DIR Length
- CMP BX,EOF ; If Not Last Cluster,
- JB READDIR1 ; Get Next Cluster
- JMP SHORT READDIR3 ; Done Reading DIR
- READDIR2: STC ; Set Error Flag
- READDIR3: POP SI ; Restore Registers
- POP DI
- POP CX
- RET ; Done
-
- READCLST: PUSH AX ; Save Registers
- PUSH CX
- PUSH DX
- MOV AX,BX ; Calculate Absolute Sector #
- SUB AX,2
- MOV CX,CLSTSEC
- MUL CX
- ADD AX,STARTSEC
- MOV DX,AX
- MOV AL,DRIVE
- PUSH BX ; Save Registers
- PUSH DI
- MOV BX,DI ; Read Cluster
- INT 25H
- POPF
- POP DI ; Restore Registers
- POP BX
- CALL NEXTCLST ; Get Next Cluster Number
- MOV AX,CLSTSEC ; Increment Buffer Pointer
- MOV CX,SECSIZE
- MUL CX
- ADD DI,AX
- POP DX ; Restore Registers
- POP CX
- POP AX
- RET ; Done
-
- NEXTCLST: CMP FATSIZE,3 ; If FAT Size = 16 Bits,
- JE NEXTCLS1
- SHL BX,1 ; Simply Read Next Cluster #
- MOV BX,FATBUF[BX]
- RET ; Done
- NEXTCLS1: PUSH AX ; Save Registers
- PUSH CX
- MOV AX,BX ; Word # = Cluster # * 1.5
- SHL AX,1
- ADD BX,AX
- SHR BX,1
- MOV BX,FATBUF[BX]
- JNC NEXTCLS2 ; If Odd, Use 12 MSB's
- MOV CL,4
- SHR BX,CL
- NEXTCLS2: AND BX,0FFFH ; Else Use 12 LSB's
- POP CX ; Restore Registers
- POP AX
- RET ; Done
-
- UPPER: PUSH AX ; Save Registers
- PUSH DX
- PUSH DI
- PUSH SI
- MOV SI,DX ; Set Up Source Index
- MOV DI,DX ; Set Up Destination Index
- UPPER1: LODSB ; Read From Source
- OR AL,AL ; If EOS, Done
- JZ UPPER3
- CMP AL,'a' ; If Lower Case,
- JL UPPER2
- CMP AL,'z'
- JG UPPER2
- SUB AL,'a'-'A' ; Convert to Upper Case
- UPPER2: STOSB ; Save in Destination
- JMP SHORT UPPER1 ; Repeat
- UPPER3: POP SI ; Restore Registers
- POP DI
- POP DX
- POP AX
- RET ; Done
-
- OUT_CLST: PUSH AX ; Save Registers
- PUSH DX
- PUSH DI
- MOV DI,OFFSET CLSTSTR[5] ; Convert Cluster # to Decimal
- CALL DEC5OUT
- CALL STRIP0 ; Strip Off Leading Zeroes
- MOV AH,9 ; Output Cluster Number
- MOV DX,OFFSET CLSTSTR
- INT 21H
- POP DI ; Restore Registers
- POP DX
- POP AX
- RET ; Done
-
- STRIP0: CMP BYTE PTR [DI],'0' ; If Character != '0', Done
- JNE STRIP1
- CMP BYTE PTR [DI+1],'0' ; If Next Character != Digit,
- JL STRIP1 ; Done
- CMP BYTE PTR [DI+1],'9'
- JG STRIP1
- MOV BYTE PTR [DI],' ' ; Change '0' to ' '
- INC DI ; Point to Next Character
- JMP SHORT STRIP0 ; Repeat
- STRIP1: RET ; Done
-
- DEC2OUT: PUSH AX ; Save Registers
- PUSH BX
- XOR AH,AH ; Clear AH
- MOV BL,10 ; AH=AX%10,AL=AX/10
- DIV BL
- ADD AX,'00' ; Convert to ASCII
- SUB DI,2
- MOV [DI],AX ; Store in String
- POP BX ; Restore Registers
- POP AX
- RET ; Done
-
- DEC4OUT: PUSH AX ; Save Registers
- PUSH BX
- MOV BL,100 ; AH=AX%100,AL=AX/100
- DIV BL
- XCHG AH,AL ; Convert 2 LSD's
- CALL DEC2OUT
- XCHG AH,AL ; Convert 2 MSD's
- CALL DEC2OUT
- POP BX ; Restore Registers
- POP AX
- RET ; Done
-
- DEC5OUT: PUSH AX ; Save Registers
- PUSH BX
- PUSH DX ; DX=AX%10000,AX=AX/10000
- MOV BX,10000
- XOR DX,DX
- DIV BX
- XCHG DX,AX ; Convert 4 LSD's
- CALL DEC4OUT
- XCHG DX,AX ; Convert MSD
- ADD AL,'0'
- SUB DI,1
- MOV [DI],AL
- POP DX ; Restore Registers
- POP BX
- POP AX
- RET ; Done
-
- DEC8OUT: PUSH AX ; Save Registers
- PUSH BX
- PUSH DX
- MOV BX,10000 ; DX=DX:AX%10000,AX=DX:AX/10000
- DIV BX
- XCHG DX,AX ; Convert 4 LSD's
- CALL DEC4OUT
- XCHG DX,AX ; Convert 4 MSD's
- CALL DEC4OUT
- POP DX ; Restore Registers
- POP BX
- POP AX
- RET ; Done
-
- FATBUF LABEL WORD
-
- CODE ENDS
-
- END CHAIN
-